package spectra.ee.web;

import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import spectra.base.util.CollectionUtil;
import spectra.base.util.StatusChecker;
import spectra.base.util.StringUtil;
import spectra.base.util.DateUtil;
import spectra.base.cm.model.ConfigProperty;
import spectra.ee.web.WebPublic;
import spectra.ee.web.common.dao.ibatis.EnvValueDaoImpl;
import spectra.ee.web.common.dao.ibatis.SystemStatusDaoImpl;
import spectra.ee.web.common.dao.IConfigPropertyDao;
import spectra.ee.web.common.dao.IEnvValueDao;
import spectra.ee.web.common.dao.ISystemStatusDao;
import spectra.ee.web.common.dao.ibatis.ConfigPropertyDaoImpl;
import spectra.ee.web.common.model.EnvValue;
import spectra.ee.web.common.model.KeyValueForm;
import spectra.ee.web.common.model.SystemStatus;

/**
 * 고객센터 환경상수정의 클래스.
 *
 * @author kwlee
 */
public class WebConfig
{
    /** 상태 체커 */
    private static StatusChecker statusChecker = new StatusChecker();

    /** 도메인ID. */
    private static String domainId;

    /** 환경변수 맵. */
    private static HashMap envMap = new HashMap();

    /** Config 맵. */
    private static HashMap configMap = new HashMap();

    /**
     * 도메인ID와 상태체크 term을 셋팅한다.
     *
     * @param strDomainId 도메인ID.
     * @param lValidTerm 상태체크 term.
     */
    public static void init(String strDomainId, long lValidTerm)
    {
        domainId = strDomainId;
        statusChecker.setValidTerm(lValidTerm);
    }

    /**
     * print메소드
     */
    public static void print()
    {
        /*try
        {
            System.out.println("--------------------------------------------------------------------------------");
            System.out.println("-- WebConfig");
            System.out.println("--------------------------------------------------------------------------------");
            System.out.println("+++domainId=" + domainId);
            System.out.println("+++validTerm=" + statusChecker.getValidTerm());
            System.out.println("+++lastLoadDateTime=" + statusChecker.getLastCheckDateTime());

            //MultiKey key = null;
            //for(Iterator it = statusChecker.getStatusMapKeySetIterator(); it.hasNext(); )
            //{
            //    key = (MultiKey) it.next();
            //    System.out.println("+++lastUpdateDateMap[" + key + "]=" + statusChecker.getStatusValue(key));
            //}

            String strKey = null;
            for(Iterator it = configMap.keySet().iterator(); it.hasNext(); )
            {
                strKey = (String) it.next();
                System.out.println("+++configMap[" + strKey + "]=" + configMap.get(strKey));
            }

            for(Iterator it = envMap.keySet().iterator(); it.hasNext(); )
            {
                strKey = (String) it.next();
                System.out.println("+++envMap[" + strKey + "]=" + envMap.get(strKey));
            }
            System.out.println("--------------------------------------------------------------------------------");
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }*/
    }

    /**
     * t_system_status 테이블로부터 리로딩할 환경변수 대상 목록을 가져온다.<br>
     * status_id = 'CONFIG_PROPERTY_LAST_UPDATE' 또는 <br>
     * domain_id = #domainId:CHAR# AND status_id = 'ENV_VALUE_LAST_UPDATE'<br>
     * 인 조건에 부합하는 목록을 가져온다.<br>
     *
     * @return 리로딩 환경변수 대상 목록. (KeyValueForm List)
     */
    private static List getReloadTargetList()
    {
        List reloadTargetList = new LinkedList();

        try
        {
            ISystemStatusDao systemStatusDao = new SystemStatusDaoImpl();
            List systemStatusList = systemStatusDao.selectSystemStatusListForWebConfig(domainId);
            int iListSize = CollectionUtil.size(systemStatusList);
            SystemStatus systemStatus = null;
            String strStatusId = null;
            String strOldUpdateDate = null;
            String strNewUpdateDate = null;

            for(int i = 0; i < iListSize; i++)
            {
                systemStatus = (SystemStatus) systemStatusList.get(i);
                strStatusId = systemStatus.getStatusId();
                strOldUpdateDate = statusChecker.getStatusValue(strStatusId);
                strNewUpdateDate = systemStatus.getStatusValue();

                if(strOldUpdateDate == null || StringUtil.isNotEqual(strOldUpdateDate, strNewUpdateDate))
                {
                    reloadTargetList.add(new KeyValueForm(strStatusId, strNewUpdateDate));
                }
            }
        }
        catch(Exception e)
        {
        }

        return reloadTargetList;
    }

    /**
     * 환경변수를 리로딩 하는 메소드.
     */
    public static void rebuild()
    {
        // 리로딩 환경변수 대상 목록을 가져온다.
        List reloadList = getReloadTargetList();
        int iListSize = CollectionUtil.size(reloadList);
        int iFailCount = 0;
        boolean bIsSuccess = false;
        KeyValueForm keyValue = null;

        // 리로딩 환경변수 대상 목록에 대해, 모두 리로딩 한다.
        for(int i = 0; i < iListSize; i++)
        {
            keyValue = (KeyValueForm) reloadList.get(i);
            bIsSuccess = reloadWebConfig(keyValue.getKey(), keyValue.getValue());
            if(bIsSuccess == false)
            {
                iFailCount++;
            }
        }

        // 리로딩에 성공하였으면, 마지막 로딩시간을 현재 시간으로 설정한다.
        if(iFailCount == 0)
        {
            statusChecker.setLastCheckDateTime(DateUtil.getCurrDateTimeStamp());
        }

        print();
    }

    /**
     * 주어진 업데이트ID(환경변수 대상ID)에 대해 환경변수를 리로딩 하는 메소드.
     *
     * @param strUpdateId 업데이트ID. (환경변수 대상ID)
     * @param strLastUpdatedDate 최종수정일자.
     * @return 성공시 true, 실패시 false.
     */
    private static boolean reloadWebConfig(String strUpdateId, String strLastUpdatedDate)
    {
        if(strUpdateId.equals(WebPublic.STATUS_ID_CONFIG_PROPERTY_LAST_UPDATE))
        {
            return loadConfigProperty(strLastUpdatedDate);
        }
        else if(strUpdateId.equals(WebPublic.STATUS_ID_ENV_VALUE_LAST_UPDATE))
        {
            return loadEnvValue(strLastUpdatedDate);
        }

        return true;
    }

    /**
     * t_config_property 테이블로 부터 web_use_flag='Y'인 환경변수를 로딩하는 메소드.
     *
     * @param strLastUpdatedDate 최종로딩시간
     * @return 성공시 true, 실패시 false.
     */
    private static boolean loadConfigProperty(String strLastUpdatedDate)
    {
        try
        {
            IConfigPropertyDao configPropertyDao = new ConfigPropertyDaoImpl();
            List configPropertyList = configPropertyDao.selectConfigPropertyListForWebConfig();
            int iListSize = CollectionUtil.size(configPropertyList);
            ConfigProperty configProperty = null;
            String strValue = null;
            String strKey = "";

            for(int i = 0; i < iListSize; i++)
            {
                configProperty = (ConfigProperty) configPropertyList.get(i);
                strValue = StringUtil.defaultString(configProperty.getValue());
                strKey = configProperty.getServiceId() + WebPublic.STRING_DELIMITER
                    + configProperty.getPropertyId();
                configMap.put(strKey, strValue);
            }

            statusChecker.putStatusValue(WebPublic.STATUS_ID_CONFIG_PROPERTY_LAST_UPDATE, strLastUpdatedDate);
        }
        catch (Exception e)
        {
            System.out.println("loadConfigProperty : " + e.getMessage());
            return false;
        }
        return true;
    }

    /**
     * t_env_value 테이블로 부터 환경변수를 로딩하는 메소드.<br>
     * - 주어진 도메인에 해당하는 환경설정 값 목록을 얻는 메소드(채팅제외).
     *
     * @param strLastUpdatedDate 최종로딩시간
     * @return 성공시 true, 실패시 false.
     */
    private static boolean loadEnvValue(String strLastUpdatedDate)
    {
        try
        {
            IEnvValueDao envValueDao = new EnvValueDaoImpl();
            List envValueList = envValueDao.selectEnvValueListForWebConfig(domainId);
            int iListSize = CollectionUtil.size(envValueList);
            EnvValue envValue = null;
            String strEnvValue = null;
            for(int i = 0; i < iListSize; i++)
            {
                envValue = (EnvValue) envValueList.get(i);
                strEnvValue = envValue.getEnvValue();
                if(strEnvValue == null)
                {
                    strEnvValue = "";
                }

                envMap.put(envValue.getEnvId(), strEnvValue);
            }

            statusChecker.putStatusValue(WebPublic.STATUS_ID_ENV_VALUE_LAST_UPDATE, strLastUpdatedDate);

            return true;
        }
        catch(Exception e)
        {
            System.out.println("loadEnvValue : " + e.getMessage());
        }

        return false;
    }

    /**
     * 기간이 만료되면 리빌드한다.
     */
    public static void rebuildIfExpireValidTerm()
    {
        if(statusChecker.isExpireValidTerm())
        {
            String strLastTime = statusChecker.getLastCheckDateTime();
            String strCurrTime = DateUtil.getCurrDateTimeStamp();

            try
            {
                System.out.println("[EE:WebConfig] reload. " + strLastTime.substring(8, 10) + ":" + strLastTime.substring(10, 12) + ":" + strLastTime.substring(12, 14) + " -> " + strCurrTime.substring(8, 10) + ":" + strCurrTime.substring(10, 12) + ":" + strCurrTime.substring(12, 14) + " (" + DateUtil.betweenSec(strLastTime, strCurrTime) + "sec term)");
            }
            catch(Exception e)
            {
                System.out.println("[EE:WebConfig] reload. " + strCurrTime.substring(8, 10) + ":" + strCurrTime.substring(10, 12) + ":" + strCurrTime.substring(12, 14) + " (initalized)");
            }
            rebuild();
        }
    }

    /**
     * 주어진 서비스ID와 프로퍼티ID에 맞는 환경설정 값을 얻는 메소드.
     *
     * @param strServiceId 서비스ID.
     * @param strPropertyId 프로퍼티ID.
     * @return 환경설정 값
     */
    public static String getConfigValue(String strServiceId, String strPropertyId)
    {
        rebuildIfExpireValidTerm();

        String strKey = strServiceId + WebPublic.STRING_DELIMITER + strPropertyId;
        Object objValue = configMap.get(strKey);
        return (objValue == null) ? null : (String) objValue;
    }
    
    /**
     * 모든 환경설정값(t_)을 담은 HashMap 객체를 리턴한다.
     * @return 환경설정
     */
    public static HashMap getAllConfigValues()
    {
    	rebuildIfExpireValidTerm();
    	return configMap;
    }

    /**
     * 주어진 환경설정ID에 맞는 환경설정 값을 얻는 메소드.
     *
     * @param strEnvId 환경설정ID
     * @return 환경설정 값
     */
    public static String getEnvValue(String strEnvId)
    {
        rebuildIfExpireValidTerm();

        Object objValue = envMap.get(strEnvId);
        return (objValue == null) ? null : (String) objValue;
    }
    
    /**
     * 모든 환경설정(t_env, t_env_values) 값을 담은 HashMap 객체를 리턴한다.
     * @return 환경설정
     */
    public static HashMap getAllEnvValues()
    {
    	rebuildIfExpireValidTerm();
    	return envMap;
    }
    
    /**
     * 모든 config 환경설정값과 env 환경설정값을 담은 모든 환경설정을 가져온다.
     * @return 모든 config, env 환경설정
     */
    public static HashMap getAllConfigEnvValues()
    {
    	rebuildIfExpireValidTerm();
    	HashMap mapAll = new HashMap();
    	mapAll.putAll(envMap);
    	mapAll.putAll(configMap);
    	return mapAll;
    }
    
    public static HashMap getAllConfigEnvValues(String delimiter)
    {
    	rebuildIfExpireValidTerm();
    	HashMap mapAll = new HashMap();
    	mapAll.putAll(envMap);

    	Set keySet = configMap.keySet();
    	Iterator keys = keySet.iterator();
    	String key = null;
    	String value = null;
    	while (keys.hasNext())
    	{
    		key = (String)keys.next();
    		value = (String)configMap.get(key);
    		key = key.replaceAll(WebPublic.STRING_DELIMITER, delimiter);
    		mapAll.put(key, value);
    	}

    	return mapAll;
    }

    /**
     * 도메인ID를 가져온다.
     *
     * @return domainId 도메인ID.
     */
    public static String getDomainId()
    {
        return domainId;
    }
}